#include "config.h"

#include <stdio.h>
#include <dirent.h>
#include <sys/param.h>

#define DBG_SUBSYS S_LIBINTERFACE

#include "adt.h"
#include "sysy_lib.h"
#include "configure.h"
#include "sysy_conf.h"
#include "ynet_net.h"
#include "net_global.h"

#include "lich_md.h"
#include "cluster.h"
#include "sysutil.h"

#include "dbg.h"


int get_nodelist(char **names, int *count, const char *site)
{
        int ret, buflen, done = 0;
        char buf[MAX_BUF_LEN], tmp[MAX_BUF_LEN], name[HOST_NAME_MAX];
        char _site[HOST_NAME_MAX];
        uint64_t offset = 0, offset2 = 0;
        struct dirent *de;
        nodeinfo_t *info;
        uuid_t _uuid;
        char uuid[MAX_NAME_LEN] = {};

        uuid_generate(_uuid);
        uuid_unparse(_uuid, uuid);

        ret = cluster_listnode_open(uuid);
        if (ret)
                GOTO(err_ret, ret);

        while (done == 0) {
                memset(buf, 0, sizeof(buf));
                ret = cluster_listnode(buf, &buflen, uuid, offset);
                if (ret)
                        GOTO(err_close, ret);

                if (buflen == 0)
                        break;

                offset2 = 0;
                info = (void *)tmp;
                dir_for_each(buf, buflen, de, offset2) {
                        DINFO("node %s, site: %s\n", de->d_name, site);
                        if (strlen(de->d_name) == 0) {
                                done = 1;
                                break;
                        } else if (buflen - offset2 < sizeof(*de) + MAX_NAME_LEN)
                                break;

                        offset += de->d_reclen;

                        char infobuf[MAX_BUF_LEN];
                        ret = node_getinfo(info, de->d_name, infobuf);
                        if (ret) {
                                continue;
                        }

                        if (!node_stat_writeable(info->stat->status)) {
                                continue;
                        }

                        // check site
                        strcpy(name, de->d_name);
                        DINFO("host %s\n", name);

                        /*
                           disk2site(name, _site);

                           if (!cluster_storage_area_is_null(site)) {
                           if (strcmp(_site, site) != 0) {
                           continue;
                           }
                           }
                           */

                }
        }

        cluster_listnode_close(uuid);
        return 0;
err_close:
        cluster_listnode_close(uuid);
err_ret:
        return ret;
}


void test_hosts_split() {
        printf("test_hosts_split -----------------------\n");

        char site[MAX_NAME_LEN];
        char rack[MAX_NAME_LEN];
        char node[MAX_NAME_LEN];
        char disk[MAX_NAME_LEN];

        hosts_split("192.168.120.121/0", site, rack, node, disk);

        printf("site %s rack %s node %s disk %s\n", site, rack, node, disk);

#if 0
        str2id("vol.1.0");
        str2id("subvol.1.0");
        str2id("raw.1.0");
#endif

        fileid_t fileid;
        md_chunk_getid("/", &fileid);

}


typedef struct {
        // MUST first element
        struct list_head hook;
        int i;
} node_t;

typedef struct {
        struct list_head node_list;
        int n;
} root_t;

void test_list() {
        int ret, i;
        root_t root;
        node_t *node;
        struct list_head *pos, *n;

        INIT_LIST_HEAD(&root.node_list);

        for (i=0; i<10; i++) {
                ret = ymalloc((void **)&node, sizeof(node_t));
                if (ret)
                        continue;

                node->i = i;
                list_add_tail(&node->hook, &root.node_list);
                root.n += 1;
        }

        (void)ret;

        list_for_each(pos, &root.node_list) {
                node = (node_t *)pos;
                printf("before i=%d\n", node->i);
        }

        // NOTE: node and hook
        list_for_each_entry(node, &root.node_list, hook) {
                printf("list_for_each_entry before i=%d\n", node->i);
        }

        list_for_each_safe(pos, n, &root.node_list) {
                node = (node_t *)pos;
                list_del(pos);
                yfree((void **)&node);
        }

        list_for_each(pos, &root.node_list) {
                node = (node_t *)pos;
                printf("after i=%d\n", node->i);
        }
}

int test_cluster_get_nodes()
{
        int i;
        cluster_node_t *val;
        vec_node_t v;
        struct timeval begin, end;
        int64_t used;

        _gettimeofday(&begin, NULL);

        vec_init(&v);

        cluster_get_nodes(&v, FALSE);

        vec_foreach(&v, val, i) {
                DINFO("i %d name %s\n", i, val->nodeinfo->nodename);
        }

        vec_destroy(&v);

        _gettimeofday(&end, NULL);
        used = _time_used(&begin, &end);
        printf("-- used %llu\n", (LLU)used);

        return 0;
}

typedef struct {
        int i;
        buffer_t buf;
} test_t;

int main() {
        int ret;

        // test_list();

        // mem_cache_init();
        // mem_hugepage_init();
        // ret = env_init("fusionstack");
        ret = env_init_simple("test");
        if (ret) {
                goto err_ret;
        }

        DINFO("Hello, world\n");

        test_t t1, t2;
        mbuffer_init(&t1.buf, 100);
        memcpy(&t2, &t1, sizeof(test_t));
        BUFFER_CHECK((&t1.buf));
        BUFFER_CHECK((&t2.buf));

        DINFO("end\n");
        return 0;

        ret = network_connect_master();
        if (unlikely(ret))
                GOTO(err_ret, ret);

        ret = stor_init(NULL, -1);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        test_hosts_split();
        DINFO("------------------------------------%s\n", ng.home);

        test_cluster_get_nodes();

        return 0;
err_ret:
        return ret;
}
